package fr.umlv.ig.xml;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import fr.umlv.ig.model.Itinerary;
import fr.umlv.ig.model.Line;
import fr.umlv.ig.model.MetroModelImpl;
import fr.umlv.ig.model.Station;

/**
 * Class used to parse a configuration XML and initialize a 
 * {@link MetroModelImpl}.
 * @author jenseric
 * @author william
 *
 */
public class MetroModelFactory extends DefaultHandler {
	/**
	 * The {@link MetroModelImpl} to initializes.
	 */
	private MetroModelImpl metroModel = new MetroModelImpl();
	
	/**
	 * The current Line during the parsing.
	 */
	private Line currentLine;
	
	/**
	 * The current Itinerary during the parsing.
	 */
	private Itinerary currentItinary;
	
	/**
	 * The current Map of stations when a line is parse.
	 */
	private Map<String, Station> currentStations;
	
	/**
	 * The current id of itinerary when we make the relation between Station.
	 */
	private int idItinerary; 
	
	/**
	 * Boolean used for waiting the end of the parsing before to allowed to 
	 * return the model with the method getModel().
	 */
	private boolean  end = false;
	

	/**
	 * Returns a MetroModelFactory.
	 * @param filename the filename of the configuration application.
	 * @return
	 * @throws ParserConfigurationException problem 
	 *         occurred during the initialization of the parsing
	 * @throws SAXException problem occurred during the parsing.
	 * @throws IOException problem associated by the parsing.
	 */
	public static MetroModelFactory newInstance(String filename) throws ParserConfigurationException, SAXException, IOException {
		MetroModelFactory metroModelFactory = new MetroModelFactory();
		SAXParserFactory saxParser = SAXParserFactory.newInstance();
		SAXParser parser = saxParser.newSAXParser();
		parser.parse(filename, metroModelFactory);
		return metroModelFactory;
	}
	

	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {

		if("line".equals(qName)) {
			currentLine= new Line(attributes.getValue("id"));
				metroModel.addLine(currentLine);
			currentStations = new HashMap<String, Station>();
		}
		if("station".equals(qName)) {
			String name = attributes.getValue("name");
			int x = Integer.parseInt(attributes.getValue("x"));
			int y = Integer.parseInt(attributes.getValue("y"));
			int time = Integer.parseInt(attributes.getValue("time"));
			Station station = new Station(name, x,y, currentLine,time);
			metroModel.addStation(currentLine, station);
			currentStations.put(station.getName(), station);
		}
		if("itinerary".equals(qName)) {
			Itinerary itinerary = new Itinerary(
					(currentStations.get(attributes.getValue("begin"))), 
					(currentStations.get(attributes.getValue("end"))));
			metroModel.addItinerary(currentLine, itinerary);
		}
		
		if("edgeConfig".equals(qName)) {
			idItinerary = Integer.parseInt(attributes.getValue("itinary"));
			currentItinary = metroModel.getItinerary(currentLine, idItinerary);
		}
		
		if("edge".equals(qName)) {
	
			Station station = currentStations.get(attributes.getValue("station"));
			Station nextStation = currentStations.get(attributes.getValue("next"));
			int waitingTime = Integer.parseInt(attributes.getValue("time"));

			if(idItinerary%2 ==0) {  
				metroModel.addNextStation(currentLine, metroModel.getEnd(currentItinary), station, nextStation);
				metroModel.setWaitingTime(station, nextStation, waitingTime);
			}
			else {
				
				metroModel.addNextStation(currentLine, metroModel.getEnd(currentItinary),nextStation, station);
				metroModel.setWaitingTime(nextStation, station, waitingTime);
			}
		}
	}
	

	
	public MetroModelImpl getMetroModelImpl() {
		if(end == false) {
			throw new IllegalStateException("the model is not ready");
		}
		return metroModel;
	}
	
	@Override
	public void endDocument() throws SAXException {
		end = true;
	}
}
